/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package co.edu.unal.bioingenium.kbmed.experimentation;

import co.edu.unal.bioingenium.kbmed.knowledge.mapping.api.Mapping;
import co.edu.unal.bioingenium.kbmed.knowledge.mapping.heuristic.Matching;
import co.edu.unal.bioingenium.kbmed.knowledge.mapping.impl.SoftMapping;
import co.edu.unal.bioingenium.kbmed.knowledge.mapping.util.TestData;
import co.edu.unal.bioingenium.kbmed.knowledge.vo.DescriptorData;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 *
 * @author Luis A Riveros
 */
public class MappingPerformance {

    private static int experimentCount = 0;

    public static void printColunmNames() {
        System.out.print("Count\t");
        System.out.print("MappingClass\t");
        System.out.print("StringMetric\t");
        System.out.print("STRING_METRIC_THRESHOLD\t");
        System.out.print("SIMILARITY_THRESHOLD\t");
        System.out.print("A1\t");
        System.out.print("A2\t");
        System.out.print("A3\t");
        System.out.print("A4\t");
        System.out.print("meanResults\t");
        System.out.print("meanPrecision\t");
        System.out.print("meanRecall\t");
        System.out.print("F-measure\t");
        System.out.print("meanPrecisionAt1\t");
        System.out.print("meanPrecisionAt5\t");
        System.out.print("meanPrecisionAt10\n");
    }

    public static void mappingTest(Mapping mapping) {
        experimentCount++;
        mapping.setVerbose(false);
        TestData testData = new TestData();
        List<DescriptorData> result;
        double meanResults = 0;
        double meanPrecision = 0;
        double meanPrecisionAt1 = 0;
        double meanPrecisionAt5 = 0;
        double meanPrecisionAt10 = 0;
        double meanRecall = 0;
        double count = 0;
        for (Integer sentenIdx : testData.getSentences().keySet()) {
            result = mapping.mapSentence(testData.getSentences().get(sentenIdx));
            meanResults += result.size();
            if (!result.isEmpty()) {
                count++;
                meanPrecision += precisionAt(result.size(), result, testData.getIdentifiedConcepts().get(sentenIdx));
                meanPrecisionAt1 += precisionAt(1, result, testData.getIdentifiedConcepts().get(sentenIdx));
                meanPrecisionAt5 += precisionAt(5, result, testData.getIdentifiedConcepts().get(sentenIdx));
                meanPrecisionAt10 += precisionAt(10, result, testData.getIdentifiedConcepts().get(sentenIdx));
                meanRecall += recallAt(result.size(), result, testData.getIdentifiedConcepts().get(sentenIdx));
            }

        }
        System.out.print(experimentCount + "\t");
        System.out.print(mapping.getClass().getName().substring(mapping.getClass().getName().lastIndexOf(".") + 1, mapping.getClass().getName().length()) + "\t");
        try {
            System.out.print(mapping.getStringMetric().getClass().getName().substring(mapping.getStringMetric().getClass().getName().lastIndexOf(".") + 1, mapping.getStringMetric().getClass().getName().length()) + "\t");
        } catch (UnsupportedOperationException ex) {
            System.out.print("-\t");
        }
        try {
            System.out.print(mapping.getSTRING_METRIC_THRESHOLD() + "\t");
        } catch (UnsupportedOperationException ex) {
            System.out.print("-\t");
        }
        System.out.print(mapping.getSIMILARITY_THRESHOLD() + "\t");
        System.out.print(Matching.getA1() + "\t");
        System.out.print(Matching.getA2() + "\t");
        System.out.print(Matching.getA3() + "\t");
        System.out.print(Matching.getA4() + "\t");
        System.out.format("%.3f\t", (double) meanResults / (double) count);
        System.out.format("%.3f\t", (double) meanPrecision / (double) count);
        System.out.format("%.3f\t", (double) meanRecall / (double) count);
        System.out.format("%.3f\t", (double) 2 * ((meanPrecision * meanRecall) / (double) (meanPrecision + meanRecall)));
        System.out.format("%.3f\t", (double) meanPrecisionAt1 / (double) count);
        System.out.format("%.3f\t", (double) meanPrecisionAt5 / (double) count);
        System.out.format("%.3f\n", (double) meanPrecisionAt10 / (double) count);


    }

    public static double recallAt(int at, List<DescriptorData> result, Set<DescriptorData> baseLine) {
        if (baseLine.isEmpty()) {
            return 1;
        }
        if (at > result.size()) {
            at = result.size();
        }
        List<DescriptorData> subList = new ArrayList<DescriptorData>();
        subList.addAll(result.subList(0, at));
        subList.retainAll(baseLine);
        return (double) subList.size() / (double) baseLine.size();
    }

    public static double precisionAt(int at, List<DescriptorData> results, Set<DescriptorData> baseLine) {
        if (at > results.size()) {
            at = results.size();
        }
        List<DescriptorData> subList = new ArrayList<DescriptorData>();
        subList.addAll(results.subList(0, at));
        subList.retainAll(baseLine);
        return (double) subList.size() / (double) at;
    }

    public static void main(String[] args) {
        double deltaWeitghs = 0.25d;
        double deltaThreshold = 0.1d;
        double[] weights = new double[4];
        double similarityThreshold, stringMetricThreshold;
        Mapping mapping = new SoftMapping();
        mapping.init();
        printColunmNames();
        mappingTest(mapping);




//
//        similarityThreshold = 0.6;
//        while (similarityThreshold <= 1.0) {
//            stringMetricThreshold = 0.6;
//            while (stringMetricThreshold <= 1.0) {
//                mapping.setSIMILARITY_THRESHOLD(similarityThreshold);
//                try {
//                    mapping.setSTRING_METRIC_THRESHOLD(stringMetricThreshold);
//                } catch (UnsupportedOperationException ex) {
//                    stringMetricThreshold = 1.1;
//                }
//                weights[0] = 0.01;
//                while (weights[0] <= 1.0) {
//                    weights[1] = 0.01;
//                    while (weights[1] <= 1.0) {
//                        weights[2] = 0.01;
//                        while (weights[2] <= 1.0) {
//                            weights[3] = 0.01;
//                            while (weights[3] <= 1.0) {
//                                Matching.setWeight(weights[0], weights[1], weights[2], weights[3]);
//                                mappingTest(mapping);
//                                weights[3] += deltaWeitghs;
//                            }
//                            weights[2] += deltaWeitghs;
//                        }
//                        weights[1] += deltaWeitghs;
//                    }
//                    weights[0] += deltaWeitghs;
//                }
//                stringMetricThreshold += deltaThreshold;
//            }
//            similarityThreshold += deltaThreshold;
//        }

    }
}
